using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.Configuration;
using System.Diagnostics;
using SpaceFight.Properties;
using SpaceFight.Units;
using SpaceFight.Units.Steering;

namespace SpaceFight{


public class Game1 : Microsoft.Xna.Framework.Game
{
	GraphicsDeviceManager graphics;
	SpriteBatch spriteBatch;

	static public ContentManager ContentMgr { get; private set; }

	public Game1()
	{
		graphics = new GraphicsDeviceManager(this);
		Content.RootDirectory = "Content";
		Camera.createInstance(new Vector3(0.0f, 50.0f, 5000.0f), Vector3.Zero, Vector3.Up);

		//IsFixedTimeStep = false;
		//graphics.SynchronizeWithVerticalRetrace = false;
		

		Components.Add(new FrameRateCounter(this));

		ContentMgr = Content;
	}

	protected override void Initialize()
	{
		base.Initialize();
	}
	UnitController m_unitController = new UnitController();

	protected override void LoadContent()
	{
		// Create a new SpriteBatch, which can be used to draw textures.
		spriteBatch = new SpriteBatch(GraphicsDevice);
		
		// set camera stuff
		Camera.getInstance().AspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /
		                                   (float)graphics.GraphicsDevice.Viewport.Height;
		Camera.getInstance().Update();

		var unitSettings = new UnitSettingsSliders();
		// create test units
		Fighter fighter2 = new Fighter();
		Fighter fighter1 = new Fighter();
		
		fighter1.Position = new Vector3(1000, 0, 300);
		fighter1.Orientation = Quaternion.CreateFromYawPitchRoll(0,0,0);
		var SI1 = fighter1.SteeringInfo;
		SI1.Target = fighter2;
		SI1.SteeringBehavior = SBType.Wander;
		
		SI1.ModelFrontVector = Vector3.Forward;
		
		SI1.WanderOffset = 100;
		SI1.WanderRadius = 20;
		SI1.WanderRate = 1.5F;
		SI1.WanderOrientation = Quaternion.Identity;
		
		unitSettings.AddSlider("WanderOffset", new SliderSettings(SI1, "WanderOffset", 0.01F, 10000));
		unitSettings.AddSlider("WanderRadius", new SliderSettings(SI1, "WanderRadius", 0.01F, 10000));
		unitSettings.AddSlider("WanderRate", new SliderSettings(SI1, "WanderRate", 0.01F, 50));
		
		
		SI1.MaxMoveSpeed    = Properties.UnitSettings.Default.MaxMoveSpeed;
		SI1.MaxAngularSpeed = MathHelper.ToRadians(Properties.UnitSettings.Default.MaxAngularSpeed);
		SI1.MaxAcceleration        = Properties.UnitSettings.Default.MaxAcceleration;
		SI1.MaxAngularAcceleration = (Properties.UnitSettings.Default.MaxAngularAcceleration);
		
		unitSettings.AddSlider("MaxMoveSpeed", new SliderSettings(SI1, "MaxMoveSpeed", 0, 1000));
		unitSettings.AddSlider("MaxAcceleration", new SliderSettings(SI1, "MaxAcceleration", 0, 20000));


		
		SI1.AlignSlowRadius = MathHelper.Pi;
		SI1.AlignTargetRadius = MathHelper.PiOver2 / 10;
		SI1.AlignTimeToTarget = 0.1F;
		
		fighter2.SteeringInfo.Target = fighter1;
		fighter2.SteeringInfo.SteeringBehavior = SBType.Arrive;
		fighter2.Orientation = Quaternion.CreateFromYawPitchRoll(MathHelper.PiOver4*2,0,0);
		
		fighter2.SteeringInfo.ArriveSlowRadius = 300;
		fighter2.SteeringInfo.ArriveTargetRadius = 100;
		fighter2.SteeringInfo.ArriveTimeToTarget = 0.1F;

		fighter2.SteeringInfo.AlignSlowRadius = MathHelper.Pi;
		fighter2.SteeringInfo.AlignTargetRadius = MathHelper.PiOver2 / 10;
		fighter2.SteeringInfo.AlignTimeToTarget = 0.1F;
		
		fighter2.SteeringInfo.MaxMoveSpeed    = Properties.UnitSettings.Default.MaxMoveSpeed;
		fighter2.SteeringInfo.MaxAngularSpeed = MathHelper.ToRadians(Properties.UnitSettings.Default.MaxAngularSpeed);
		fighter2.SteeringInfo.MaxAcceleration        = Properties.UnitSettings.Default.MaxAcceleration;
		fighter2.SteeringInfo.MaxAngularAcceleration = MathHelper.ToRadians(Properties.UnitSettings.Default.MaxAngularAcceleration);
		
		m_unitController.Add(fighter1);
		m_unitController.Add(fighter2);
	}

	protected override void UnloadContent()
	{
	}
	int m_oldMouseX = 0;
	int m_oldMouseY = 0;

	//int m_fps = 0;
	//TimeSpan m_prev = new TimeSpan();
	
	protected override void Update(GameTime gameTime)
	{
	/*	// test debug info viewer
		DebugInfoViewer.DebugMain.ShowDebugInfo("TotalGameTime",   gameTime.TotalGameTime.ToString(), this);
		DebugInfoViewer.DebugMain.ShowDebugInfo("TotalRealTime",   gameTime.TotalRealTime.ToString(), this);
		DebugInfoViewer.DebugMain.ShowDebugInfo("ElapsedGameTime", gameTime.ElapsedGameTime.ToString(), this);
		DebugInfoViewer.DebugMain.ShowDebugInfo("ElapsedRealTime", gameTime.ElapsedRealTime.ToString(), this);
		DebugInfoViewer.DebugMain.ShowDebugInfo("Fps(quick)", (1 / gameTime.ElapsedRealTime.TotalSeconds).ToString(), this);

		// count frames in a second for fps
		++m_fps;
		if (m_prev <= gameTime.TotalRealTime)
		{
			m_prev = gameTime.TotalRealTime + new TimeSpan(0, 0, 1);
			DebugInfoViewer.DebugMain.ShowDebugInfo("Fps(counted)", m_fps.ToString(), this);
			m_fps = 0;
		}
		*/
		int movespeed = Settings.Default.Movespeed;
		if (Keyboard.GetState().IsKeyDown(Keys.LeftShift))
		{
			movespeed *= Settings.Default.ShiftMultiplier;
		}
		if(Keyboard.GetState().IsKeyDown(Keys.Z))
		{
			Camera.getInstance().moveForward(gameTime.ElapsedGameTime.TotalSeconds * movespeed);
		}
		if (Keyboard.GetState().IsKeyDown(Keys.S))
		{
			Camera.getInstance().moveForward(-gameTime.ElapsedGameTime.TotalSeconds * movespeed);
		}
		if (Keyboard.GetState().IsKeyDown(Keys.D))
		{
			Camera.getInstance().moveRight(gameTime.ElapsedGameTime.TotalSeconds * movespeed);
		}
		if (Keyboard.GetState().IsKeyDown(Keys.Q))
		{
			Camera.getInstance().moveRight(-gameTime.ElapsedGameTime.TotalSeconds * movespeed);
		}
		if(Mouse.GetState().RightButton == ButtonState.Pressed)
		{
			Camera.getInstance().rotateAroundRight(-(Mouse.GetState().Y - m_oldMouseY) * 
			                                       gameTime.ElapsedGameTime.TotalSeconds * 0.5);
			Camera.getInstance().rotateAroundUp(-(Mouse.GetState().X - m_oldMouseX) * 
			                                    gameTime.ElapsedGameTime.TotalSeconds * 0.5);
		}
		m_oldMouseX = Mouse.GetState().X;
		m_oldMouseY = Mouse.GetState().Y;
		Camera.getInstance().Update();

		m_unitController.Update(gameTime);
		
		base.Update(gameTime);
	}

	protected override void Draw(GameTime gameTime)
	{
		GraphicsDevice.Clear(Color.CornflowerBlue);
		
		GraphicsDevice.RenderState.DepthBufferEnable = true;
		GraphicsDevice.RenderState.AlphaBlendEnable = false;
		
		ModelRenderer.Draw(gameTime);
		
		/* // Testing code to draw a line in 3d space
		BasicEffect effect = new BasicEffect(GraphicsDevice, null);
		effect.VertexColorEnabled = true;
		effect.LightingEnabled = false;
		VertexDeclaration vertDecl = new VertexDeclaration(GraphicsDevice, VertexPositionColor.VertexElements);
		
		effect.World = Matrix.Identity;
		effect.View = Camera.getInstance().View;
		effect.Projection = Camera.getInstance().Projection;
		
		GraphicsDevice.VertexDeclaration = vertDecl;
		
		var pointList = new VertexPositionColor[2];

		pointList[0] = new VertexPositionColor(new Vector3(1000, 0, 0), Color.Red);
		pointList[1] = new VertexPositionColor(new Vector3(1000, 1000, 0), Color.Red);
		// Initialize an array of indices of type short.
		var lineListIndices = new short[2];
		lineListIndices[0] = (short)(0);
		lineListIndices[1] = (short)(1);

		
		effect.Begin();
		foreach (EffectPass pass in effect.CurrentTechnique.Passes)
		{
			pass.Begin();

			GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>(
					PrimitiveType.LineList,
					pointList,
					0,  // vertex buffer offset to add to each element of the index buffer
					2,  // number of vertices in pointList
					lineListIndices,  // the index buffer
					0,  // first index element to read
					1   // number of primitives to draw
				);

			pass.End();
		}
		effect.End();
		//*/
		base.Draw(gameTime);
	}
}
}
